extends Character
class_name Player

enum State {
	MOVE,
	JUMP,
	FALL,
	DASH,
}



@export var bridge_bag:Array[PackedScene]
@export var state_machine:StateMachine
@export var build_time_scale:float
@export var push_strength:float = 20
@export var max_dash_count: int = 2

@onready var sprite_2d: Sprite2D = $Body/Sprite2D
@onready var input_handler: InputHandler = %InputHandler
@onready var interact_area: Area2D = $Body/InterActArea
@onready var particles_manager: Node2D = $ParticlesManager
@onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D

var is_dead:bool
var is_in_dia:bool
var last_input_position:Vector2
var current_dash_count: int = 0
var dash_enabled: bool = true

var in_build:bool:
	set(v):
		in_build = v
		if v:
			GameEvents.player_in_build.emit()
		else:
			GameEvents.player_out_build.emit()

var can_interact:bool
var can_pre_build: bool = true
var current_npc:Npc

func _ready() -> void:
	Global.player = self
	platform_on_leave = CharacterBody2D.PLATFORM_ON_LEAVE_DO_NOTHING
	input_handler.interact_pressed.connect(on_interact_pressed)
	input_handler.pre_build_pressed.connect(on_pre_build_pressed)
	
	
	
	DialogHandler.dialogue_start.connect(on_dialogue_start)
	DialogHandler.dialogue_end.connect(on_dialogue_end.unbind(1))
	GameEvents.stage_entered.connect(on_stage_entered)
	
	
	interact_area.body_entered.connect(func(_body): 
		can_interact = true
		current_npc = _body
		)
	interact_area.body_exited.connect(func(_body): 
		can_interact = false
		current_npc = null
		)
	

	
	state_machine.add_state("move", PlayerStateMove.new())
	state_machine.add_state("jump", PlayerStateJump.new())
	state_machine.add_state("fall", PlayerStateFall.new())
	state_machine.add_state("dash", PlayerStateDash.new())

	state_machine.start("move")
	
	if Global.current_setting.get("MODE",2) == 0:
		jump_speed *= 1.1
		dash_speed *= 1.1
		max_energy += 1
	
	await get_parent().ready
	energy_change.emit(current_energy/max_energy)
	
	current_dash_count = 1
	update_can_dash()



func _process(delta: float) -> void:
	super._process(delta)
	if Engine.get_process_frames() % int(2/Engine.time_scale) == 0:
		create_canying()

func _physics_process(delta: float) -> void:
	super._physics_process(delta)
	
	if is_on_floor_only():
		if current_dash_count < 1:
			if Global.current_setting.get("MODE",2) > 0:
				restore_dash(1)
			else:
				restore_dash(2)
	
	#push_blocks()

			
func set_dash(bo: bool):
	dash_enabled = bo
	update_can_dash()

func update_can_dash():
	var can = dash_enabled and current_dash_count > 0
	can_dash = can
	input_handler.set_ability("dash", can)

func consume_dash():
	if current_dash_count > 0:
		current_dash_count -= 1
	update_can_dash()

func restore_dash(amount: int):
	current_dash_count = min(current_dash_count + amount, max_dash_count)
	update_can_dash()

func add_dash():
	restore_dash(1)



func set_move(bo: bool):
	super.set_move(bo)
	input_handler.set_ability("move",bo)

func set_jump(bo: bool):
	super.set_jump(bo)
	input_handler.set_ability("jump",bo)

func on_interact_pressed() -> void:
	if can_interact && current_npc != null:
		current_npc.action()

func on_pre_build_pressed() -> void:
	if can_pre_build:
		if in_build:
			Engine.time_scale = 1
			in_build = false
		else:
			Engine.time_scale = build_time_scale
			in_build = true
			MusicPlayer.stop_all_sfx()
		

func bounce(direction: Vector2) -> void:
	# 直接用传入方向作为反弹方向，实现任意方向反弹
	var dash_direction = direction.normalized()
	state_machine.change_state("dash", {"dash_direction": direction,"not_emit": false})
	set_dash(true)
	set_jump(true)

func set_paused(bo: bool):
	super.set_paused(bo)
	can_interact = !bo

	

func create_canying() -> void:
	if is_dash:
		var c = Canying.instantiate()
		c.global_position = global_position - Vector2(0, 60)
		var properties := [
			"texture",
			"hframes",
			"vframes",
			"frame",
			"scale",
		]
		
		for i in properties:
			c.set(i, sprite_2d.get(i))
		if heading == Vector2.LEFT:
			c.scale.x *= -1  
		
		get_parent().add_child(c)

func on_save_game(save_datas:Array[SavedData]) -> void:
	var save_data = SavedData.new()
	save_data.position = global_position
	save_data.current_energy = current_energy
	save_data.max_energy = max_energy
	save_datas.append(save_data)

func on_load_game(save_data:SavedData) -> void:
	global_position = save_data.position
	current_energy = save_data.current_energy
	max_energy = save_data.max_energy
	

func die() -> void:
	if !is_dead:
		if in_build:
			on_pre_build_pressed()
		var particles :Array = particles_manager.get_children()
		for i in particles:
			i.emitting = true
		GameEvents.player_died.emit()
		MusicPlayer.play_sfx("Die")
		is_dead = true
		freeze()
		can_pre_build = false
		health_component.damage(health_component.max_health)

func on_stage_entered() -> void:
	health_component.damage(-health_component.max_health)
	current_energy = max_energy
	can_pre_build = true
	await get_tree().create_timer(.8).timeout
	if !is_in_dia:
		set_paused(false)

func freeze() -> void:
	velocity = Vector2.ZERO
	set_paused(true)

func on_dialogue_start(_id:String, bo: bool) -> void:
	if bo:
		if in_build:
			on_pre_build_pressed()
		is_in_dia = true
		freeze()
		can_pre_build = false


func on_dialogue_end() -> void:
	if is_in_dia:
		is_in_dia = false
		set_paused(false)
		can_pre_build = true
